package jwt

import (
	"errors"
	"net/http"
	"strings"
	"time"
	"zzxq/common/codes"

	jwtgo "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

type MyClaims struct {
	Uid int
	jwtgo.StandardClaims
}

const TokenExpire = time.Hour * 200

// const TokenExpire = time.Minute

var MySecret = []byte("my secret")

//生产token
func GenToken(uid int) (string, error) {
	claims := MyClaims{
		uid,
		jwtgo.StandardClaims{
			Id:        "focus.com",                        //身份标识
			IssuedAt:  time.Now().Unix(),                  //签发时间
			ExpiresAt: time.Now().Add(TokenExpire).Unix(), //过期时间
		},
	}

	token := jwtgo.NewWithClaims(jwtgo.SigningMethodHS256, claims)

	return token.SignedString(MySecret)

}

//解析token
func ParseToken(tokenString string) (*MyClaims, error) {
	token, err := jwtgo.ParseWithClaims(tokenString, &MyClaims{}, func(t *jwtgo.Token) (interface{}, error) {
		return MySecret, nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token-go")
}

//中间键
func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			//处理可以不用登录的url
			if _, ok := nologin[c.Request.RequestURI]; ok {
				c.Set("uid", 0)
				return
			}

			c.JSON(http.StatusOK, gin.H{
				"code": codes.ERRLOGINAUTH,
				"msg":  codes.GetMsg(codes.ERRLOGINAUTH),
			})
			c.Abort()
			return
		}

		// 按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusOK, gin.H{
				"code": codes.ERRLOGINFORMAT,
				"msg":  codes.GetMsg(codes.ERRLOGINFORMAT),
			})

			c.Abort()
			return
		}

		// parts[1]是获取到的tokenString，我们使用之前定义好的解析JWT的函数来解析它
		mc, err := ParseToken(parts[1])
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code": codes.ERRLOGINTOKEN,
				"msg":  codes.GetMsg(codes.ERRLOGINTOKEN),
			})
			c.Abort()
			return
		}

		// 将当前请求的username信息保存到请求的上下文c上
		c.Set("uid", mc.Uid)

		c.Next() // 后续的处理函数可以用过c.Get("uid")来获取当前请求的用户信息
	}
}
